package de.tu_darmstadt.gdi1.xcom.tests.testcases.students;

import static org.junit.Assert.*;

import org.junit.Before;
import org.junit.Test;

import de.tu_darmstadt.gdi1.xcom.tests.adapters.XcomTestAdapterLevel1;

/**
 * 
 * Tests if the action-points are decreased correctly
 * 
 * @author Lukas Schwoebel
 *
 */
public class ActionPointsTest {
	
	private XcomTestAdapterLevel1 testAdapter;
	
	
	/**
	 * @throws java.lang.Exception
	 */
	@Before
	public void setUp() throws Exception {
		testAdapter = new XcomTestAdapterLevel1();
	}

	/**
	 * Test method for {@link de.tu_darmstadt.gdi1.xcom.tests.adapters.XcomTestAdapterLevel1#actionPointsLeft()}.
	 */
	@Test
	public final void testRotateUntilEnd() {
		testAdapter.loadLevelFromString(TestLevel.testLevel);

		int i = TestLevel.actionPoints;
		// first check if action points are 75 per default
		assertEquals("The action-points should be "+TestLevel.actionPoints+" after loading of the level", TestLevel.actionPoints, testAdapter.actionPointsLeft());
		while(i > 0) {
			testAdapter.rotateActivePlayer(true);
			i--;
		}
		// now check if action points are zero
		assertEquals("The action-points should be 0 after "+TestLevel.actionPoints+" rotations", 0, testAdapter.actionPointsLeft());	
	}

	/**
	 * Test method for {@link de.tu_darmstadt.gdi1.xcom.tests.adapters.XcomTestAdapterLevel1#actionPointsLeft()}.
	 */
	@Test
	public final void testWalkThroughLevelUntilEnd() {
		testAdapter.loadLevelFromString(TestLevel.testLevel);
		
		// first check if action points are 75 per default
		assertEquals("The action-points should be "+TestLevel.actionPoints+" after loading of the level", TestLevel.actionPoints, testAdapter.actionPointsLeft());
		
		testAdapter.performActionForActivePlayer();	// 72
		testAdapter.rotateActivePlayer(false);		// 71
		testAdapter.performActionForActivePlayer();	// 68
		testAdapter.rotateActivePlayer(false);		// 67
		// kill the monster
		testAdapter.performActionForActivePlayer();	// 57
		// now check if action points are 57
		assertEquals("The action-points should be 57 after walking through the level", 57, testAdapter.actionPointsLeft());	
		// now walk up and down
		for(int i = 0; i < 3; i++) {
			testAdapter.performActionForActivePlayer();	// 54 || 37 || 20
			testAdapter.performActionForActivePlayer();	// 51 || 34 || 17
			testAdapter.performActionForActivePlayer();	// 48 || 31 || 14
			testAdapter.performActionForActivePlayer();	// 45 || 28 || 11
			testAdapter.performActionForActivePlayer();	// 42 || 25 || 8
			testAdapter.rotateActivePlayer(true);		// 41 || 24 || 7
			testAdapter.rotateActivePlayer(true);		// 40 || 23 || 6
		}
		testAdapter.performActionForActivePlayer();	// 3
		testAdapter.performActionForActivePlayer();	// 0
		
		// now check if action points are zero
		assertEquals("The action-points should be 0 after walking through the level", 0, testAdapter.actionPointsLeft());	
	}
	

	/**
	 * Test method for {@link de.tu_darmstadt.gdi1.xcom.tests.adapters.XcomTestAdapterLevel1#actionPointsLeft()}.
	 */
	@Test
	public final void testActionpointsCorrectDecremented() {
		testAdapter.loadLevelFromString(TestLevel.testLevel);
		
		int i = TestLevel.actionPoints;
		// first check if action points are 75 per default
		assertEquals("The action-points should be "+TestLevel.actionPoints+" after loading of the level", TestLevel.actionPoints, testAdapter.actionPointsLeft());
			
		// walking costs 3 points
		testAdapter.performActionForActivePlayer(); i -= 3;
		assertEquals("A walking action should cost 3 actionpoints", i, testAdapter.actionPointsLeft());
		
		// rotating should cost 1 point
		testAdapter.rotateActivePlayer(true); // rotate clockwise
		assertEquals("A rotation action should cost 1 actionpoint", --i, testAdapter.actionPointsLeft());
		testAdapter.rotateActivePlayer(false); // rotate counter-clockwise
		assertEquals("A rotation action should cost 1 actionpoint", --i, testAdapter.actionPointsLeft());
		
		// now walk to the next enemy and shoot it
		testAdapter.rotateActivePlayer(false); --i;
		testAdapter.performActionForActivePlayer(); i -= 3;
		testAdapter.rotateActivePlayer(false); --i;
		
		// test if actionpoints are still equal
		assertEquals("Actionpoints should be "+i+" after four rotations and two movement actions", i, testAdapter.actionPointsLeft());
		
		// now kill the enemy
		testAdapter.performActionForActivePlayer(); i -= 10;
		assertEquals("Shooting should cost 10 actionpoints", i, testAdapter.actionPointsLeft());
	}
	

	/**
	 * Test method for {@link de.tu_darmstadt.gdi1.xcom.tests.adapters.XcomTestAdapterLevel1#actionPointsLeft()}.
	 */
	@Test
	public final void testNoChangeWithZeroActionpoints() {
		testAdapter.loadLevelFromString(TestLevel.testLevel);
		
		String expected1special =
			"############\n" +
			"##...#######\n" +
			"##.@.##...##\n" +
			"##..###Z..##\n" +
			"#c#.####=###\n" +
			"#.@..##Z..##\n" +
			"#...@....Z##\n" +
			"############";
		String expected1regular =
			"############\n" +
			"##...#######\n" +
			"##.@.##...##\n" +
			"##..###Z..##\n" +
			"###.####.###\n" +
			"#.@..##Z..##\n" +
			"#...@....Z##\n" +
			"############";		
		
		int i = TestLevel.actionPoints;
		// first check if action points are 75 per default
		assertEquals("The action-points should be "+TestLevel.actionPoints+" after loading of the level", TestLevel.actionPoints, testAdapter.actionPointsLeft());
			
		// do some movement and rotations until we have 0 actionpoints
		testAdapter.performActionForActivePlayer(); i -= 3;		// 72
		testAdapter.rotateActivePlayer(false); i--;				// 71
		testAdapter.performActionForActivePlayer(); i -= 3;		// 68
		testAdapter.rotateActivePlayer(false); i--;				// 67
		testAdapter.performActionForActivePlayer(); i -= 10;	// 57
		testAdapter.performActionForActivePlayer(); i -= 3;		// 54
		testAdapter.rotateActivePlayer(true); i--;				// 53
		testAdapter.performActionForActivePlayer();	i -= 10;	// 43
		testAdapter.performActionForActivePlayer(); i -= 3;		// 40
		testAdapter.rotateActivePlayer(true); i--;				// 39
		testAdapter.performActionForActivePlayer(); i -= 3;		// 36
		testAdapter.rotateActivePlayer(true); i--;				// 35
		testAdapter.performActionForActivePlayer(); i -= 3;		// 32
		testAdapter.rotateActivePlayer(true);					// 31
		testAdapter.performActionForActivePlayer();				// 28
		testAdapter.performActionForActivePlayer();				// 25
		testAdapter.performActionForActivePlayer();				// 22
		testAdapter.performActionForActivePlayer();				// 19
		testAdapter.performActionForActivePlayer();				// 16
		testAdapter.rotateActivePlayer(true);					// 15
		testAdapter.rotateActivePlayer(true);					// 14
		testAdapter.performActionForActivePlayer();				// 11
		testAdapter.performActionForActivePlayer();				// 8
		testAdapter.performActionForActivePlayer();				// 5
		testAdapter.performActionForActivePlayer();				// 2
		
		String levelRep = testAdapter.levelRepresentationAsString().trim();
		// now check the level
		assertTrue("The string representation is not correct, expected: \n" + expected1regular +"\nwas:\n" + levelRep,
				(levelRep.equals(expected1regular) || levelRep.equals(expected1special)));
		
		// do a movement action, should not be possible, only 2 points left
		testAdapter.performActionForActivePlayer();
		assertTrue("The string representation is not correct, expected: \n" + expected1regular +"\nwas:\n" + levelRep,
				(levelRep.equals(expected1regular) || levelRep.equals(expected1special)));
		// check actionpoints still 2
		assertEquals("An illegal movement was done, actionpoints should be 2, no movement possible", 2, testAdapter.actionPointsLeft());
		
		// now do 2 rotations to get zero points
		testAdapter.rotateActivePlayer(true); testAdapter.rotateActivePlayer(true);
		// actionpoints should be zero
		assertEquals("Action points should be zero by now", 0, testAdapter.actionPointsLeft());
		
		// two rotations, should not be executed
		testAdapter.rotateActivePlayer(true);
		testAdapter.rotateActivePlayer(true);
		
		int lookdirection = testAdapter.activePlayerLookingToDirection();
		assertEquals("The look-direction of the active player is wrong, should be South (=3), was "+lookdirection, 3, lookdirection);
	}

	/**
	 * Test method for {@link de.tu_darmstadt.gdi1.xcom.tests.adapters.XcomTestAdapterLevel1#actionPointsLeft()}.
	 */	
	@Test
	public final void testOnlyCurrentPlayerChanged() {
		testAdapter.loadLevelFromString(TestLevel.testLevel);
		
		int i = TestLevel.actionPoints;
		// do some actions here
		testAdapter.performActionForActivePlayer(); i -= 3;		// 72
		testAdapter.rotateActivePlayer(false); i--;				// 71
		testAdapter.performActionForActivePlayer(); i -= 3;		// 68
		testAdapter.rotateActivePlayer(false); i--;				// 67
		testAdapter.performActionForActivePlayer(); i -= 10;	// 57
		testAdapter.performActionForActivePlayer(); i -= 3;		// 54
		
		// now test if the other players still have the same amount of points as in the beginning
		testAdapter.changeActivePlayer(2, 5);
		assertEquals("The other players should not change their actionpoints", TestLevel.actionPoints, testAdapter.actionPointsLeft());
		testAdapter.changeActivePlayer(4, 6);
		assertEquals("The other players should not change their actionpoints", TestLevel.actionPoints, testAdapter.actionPointsLeft());
		testAdapter.changeActivePlayer(3, 2);
		assertEquals("After changing the player, he should keep his actionpoints", i, testAdapter.actionPointsLeft());
	}
}
